#! /bin/sh
# PCP QA Test No. 255
# exercise pmcd <-> pmda version exchange
# Bug #508731
#
# Copyright (c) 1995-2002 Silicon Graphics, Inc.  All Rights Reserved.
# Copyright (c) 2017 Red Hat, Inc.  All Rights Reserved.
#

seq=`basename $0`
echo "QA output created by $seq"

# get standard filters
. ./common.product
. ./common.filter
. ./common.check

_check_job_scheduler
[ -d $PCP_PMDAS_DIR/simple ] || _notrun "simple PMDA directory is not installed"

rm -f $seq.out
_get_libpcp_config
if $ipv6 ; then
    ln $seq.out.ipv6 $seq.out || exit 1
else
    ln $seq.out.nonipv6 $seq.out || exit 1
fi

signal=$PCP_BINADM_DIR/pmsignal
status=1	# failure is the default!
errlist=''
trap "_cleanup; exit \$status" 0 1 2 3 15

_stop_auto_restart pmcd

echo "=== I am PID $$" >>$seq_full
echo "=== /tmp files" >>$seq_full
$sudo ls -l /tmp/[0-9][0-9]*.* >>$seq_full 2>&1
echo "=== config files" >>$seq_full
ls -l $PCP_PMCDCONF_PATH $PCP_PMCDOPTIONS_PATH >>$seq_full

unset ROOT MAKEFLAGS

simple_domain=253
broken_domain=249
num_warn=0

# pmcd may be quite some distance away
#
PMCD_CONNECT_TIMEOUT=30
PMCD_REQUEST_TIMEOUT=30
export PMCD_CONNECT_TIMEOUT PMCD_REQUEST_TIMEOUT

_filter_ins()
{
    sed \
	-e '/^Installing .mchart view*/d' \
	-e 's/.* \(hash table entries\)/  NNN \1/' \
	-e 's/.* \(non-leaf nodes\)/  NNN \1/' \
	-e 's/.* \(leaf nodes\)/  NNN \1/' \
	-e 's/.* \(bytes of symbol table\)/  NNN \1/'
}

# Note
#  on OpenBSD signaller pid is apparently not filled in, so we see
#    [DATE] pmcd(PID) Info: pmcd caught SIGTERM from unknown process
#  instead of
#    [DATE] pmcd(PID) Info: pmcd caught SIGTERM from pid=N uid=N
#
_filter_pmcd()
{
    _filter_pmcd_log \
    | sed \
    	-e "/^simple.*bin/s/$simple_domain[ 	]*[0-9]*[ 	]*[0-9]*[ 	]*[0-9]*/SIMPLE PID FD FD/" \
    	-e "/^simple.*dso/s/$simple_domain/SIMPLE/" \
    	-e "/^broken.*bin/s/$broken_domain[ 	]*[0-9]*[ 	]*[0-9]*[ 	]*[0-9]*/BROKEN PID FD FD/" \
	-e "s/[1-2][ 	]dso.*linux_init/LINUX DSO/" \
	-e "s;$PCP_PMDAS_DIR;PCP_PMDAS_DIR;g" \
	-e "s/ISA\.//g" \
	-e "s/ \[(nil)]//g" \
	-e "s/cmd=.*pmdas\/broken./cmd=/" \
	-e "s/ fd=[0-9]*/ fd=FD/" \
	-e "s/\.$DSO_SUFFIX/.\$DSO_SUFFIX/g" \
	-e '/UNIX_DOMAIN_SOCKET/d' \
	-e 's/ i:[0-9]/ i:?/' \
	-e '/SIGTERM from unknown process/s//SIGTERM from pid=N uid=N/' \
	-e "s@$tmp.broken@broken@g" \
	-e "s@$tmp@TMP@g" \
    | $PCP_AWK_PROG '
BEGIN				{ skip = 0 }
/client connection from/	{ print; print "..."; skip=1; next }
skip == 1 && NF == 0		{ skip = 0 }
skip == 1			{ next }
				{ print }'
}

_filter_init()
{
    sed \
    	-e "s/$$/PID/g" \
    | _filter_pcp_start
}

# Remove the PMDA and restore pmcd.conf
#
_cleanup()
{
    echo ""
    echo "=== Removing broken_pmda ==="
    cd $here/pmdas/broken
    $sudo ./broken_Remove
    cd $here

    echo "=== Resetting pmcd.conf back to original state ==="
    _restore_config $PCP_PMCDCONF_PATH
    echo "=== Resetting pmcd.options back to original state ==="
    _restore_config $PCP_PMCDOPTIONS_PATH
    echo "=== Restart PMCD ==="
    _service pmcd restart 2>&1 | _filter_pcp_restart
    _wait_for_pmcd
    _restore_auto_restart pmcd
    _service pmlogger restart 2>&1 | _filter_pcp_restart
    _wait_for_pmlogger
    if [ -f $tmp.log ]
    then
	echo "=== Filter pmcd.log ==="
	cat $tmp.log | _filter_pmcd
	echo '=== pmcd log' >>$seq_full
	cat $tmp.log >>$seq_full
    fi
    for f in $tmp.*.log
    do
	echo '=== $f' >>$seq_full
	cat $f>>$seq_full
    done
    echo "=== Restoring crontab ==="
    _restore_job_scheduler $tmp.cron $tmp.systemd $sudo
    [ -f $PCP_PMDAS_DIR/simple/simple.conf.$seq ] && _restore_config $PCP_PMDAS_DIR/simple/simple.conf

    echo "=== /tmp files" >>$seq_full
    $sudo ls -l /tmp/[0-9][0-9]*.* >>$seq_full 2>&1
    echo "=== config files" >>$seq_full
    ls -l $PCP_PMCDCONF_PATH $PCP_PMCDOPTIONS_PATH >>$seq_full

    $sudo rm -rf $tmp.*
}

# Removing systemd timers or cron entries that may collide
#
echo "=== Removing potential cron conflicts ==="
_remove_job_scheduler $tmp.cron $tmp.systemd $sudo

# Install broken pmda namespace
#
echo "=== Install broken namespace ==="
cd $here/pmdas/broken
if pmnsmerge $PCP_VAR_DIR/pmns/root ./root $tmp.pmns
then
    :
else
    echo "Error: pmnsmerge failed!"
    exit
fi
$sudo cp $tmp.pmns $PCP_VAR_DIR/pmns/root
$sudo $signal -a -s HUP pmcd >/dev/null 2>&1
_wait_for_pmcd || _exit 1
echo "=== Broken PMNS ==="
if pminfo broken
then
    :
else
    echo "Unable to install broken namespace, exiting"
    exit
fi

# Build simple agent
#
echo "=== Building simple agent ==="
cd $PCP_PMDAS_DIR/simple

# get rid of warnings from simple if no config exists
#
[ -f $PCP_PMDAS_DIR/simple/simple.conf ] && _save_config $PCP_PMDAS_DIR/simple/simple.conf
echo "sec,min,hour" >$tmp.simple.conf
$sudo cp $tmp.simple.conf simple.conf

if $sudo $PCP_MAKE_PROG > $tmp.make 2>&1
then
    echo "PMDA built"
else
    echo "Unable to build the simple PMDA:"
    cat $tmp.make
    exit
fi
sed -e "/^@ SIMPLE/s/SIMPLE/$simple_domain/" < help \
| $sudo $PCP_BINADM_DIR/newhelp -v 2 -o help
echo "Help generated"
cd $here

# Replace pmcd.options
#
echo "=== Replacing pmcd.options ==="
_save_config $PCP_PMCDOPTIONS_PATH
cat << end-of-file > $tmp.newoptions
# New pmcd.options file created by PCP QA test $seq
#
-t 10
-l $tmp.log
-T 0
end-of-file

$sudo cp $tmp.newoptions $PCP_PMCDOPTIONS_PATH
# Do not restart pmcd here, do it after changing pmcd.conf later

_renew_pmcd()
{
    echo "=== Restarting PMCD with minimal PMDAs ==="
    if [ -f $tmp.newconf ]
    then
	$sudo cp $tmp.newconf $PCP_PMCDCONF_PATH
	$sudo $signal -a -s HUP pmcd >/dev/null 2>&1
	sleep 4
	_wait_for_pmcd || _exit 1
    else
	echo caller - $1 - has not created $tmp.newconf !!!
    fi
}

# Install a standard pmda, but do not mess with the namespace
#
_agent_install()
{
    agent=$1
    domain=$2
    daemon=$3
    path=$PCP_PMDAS_DIR/$agent

    echo "=== Installing $agent ==="
    cp $tmp.newconf $tmp.latest
    if $daemon
    then
	cat << end-of-file >> $tmp.latest
# Installed by PCP QA test $seq on `date`
$agent	$domain	pipe	binary	$path/pmda$agent -d $domain -l $tmp.$agent.log
end-of-file
    else
    	cat << end-of-file >> $tmp.latest
# Installed by PCP QA test $seq on `date`
$agent	$domain	dso	${agent}_init	$path/pmda_$agent.$DSO_SUFFIX
end-of-file
    fi

    $sudo cp $tmp.latest $PCP_PMCDCONF_PATH
    $sudo $signal -a -s HUP pmcd >/dev/null 2>&1
    sleep 4
    _wait_for_pmcd || _exit 1

    if _check_agent $agent
    then
    	echo "$agent is alive and well"
    else
    	echo "Failed to install $agent"
	exit
    fi
}

# Remove a pmda
#
_agent_remove()
{
    agent=$1

    echo "=== Removing $agent ==="
    _renew_pmcd _agent_remove

    if _check_agent $agent
    then
    	echo "Failed to remove $agent"
	exit
    else
    	echo "$agent was removed"
    fi
}

# Install broken pmda
#
_broken_install()
{
    agent=$1
    ver=$2

    echo "=== Installing $agent ==="
    cp $tmp.newconf $tmp.latest
    # need PMDA executable someplace user $PCP_USER (pmcd) can read it
    #
    cp $here/pmdas/broken/$agent $tmp.$agent
    cat << end-of-file >> $tmp.latest
# Installed by PCP QA test $seq on `date`
broken	$broken_domain	pipe	binary	$tmp.$agent -d $broken_domain -l $tmp.broken.log
end-of-file

    $sudo cp $tmp.latest $PCP_PMCDCONF_PATH
    $sudo $signal -a -s HUP pmcd >/dev/null 2>&1
    sleep 4
    _wait_for_pmcd || _exit 1

    if _check_agent broken
    then
    	echo "$agent is alive and well...hang on there should be some warnings"
	pminfo -b 1 -f broken
	exit
    elif [ "$num_warn" -ne 5 ]
    then
    	echo "Failed to properly install $agent, expected 4 warnings"
	exit
    else
    	echo "$agent is alive and as well as can be expected"
    fi
}

# Copy and replace pmcd.conf
#
_save_config $PCP_PMCDCONF_PATH
cat << end-of-file > $tmp.newconf
# pmcd.conf installed by PCP QA test $seq
#
end-of-file

if [ $PCP_PLATFORM = linux ]
then
    cat >>$tmp.newconf  <<End-of-File
# from qa/$seq
linux   60      dso     linux_init      $PCP_PMDAS_DIR/linux/pmda_linux.so
pmcd    2       dso     pmcd_init       $PCP_PMDAS_DIR/pmcd/pmda_pmcd.so
End-of-File
elif [ $PCP_PLATFORM = darwin ]
then
    cat >>$tmp.newconf  <<End-of-File
# from qa/$seq
darwin  78      dso     darwin_init     $PCP_PMDAS_DIR/darwin/pmda_darwin.dylib
pmcd    2       dso     pmcd_init       $PCP_PMDAS_DIR/pmcd/pmda_pmcd.dylib
End-of-File
elif [ $PCP_PLATFORM = solaris ]
then
    cat >>$tmp.newconf  <<End-of-File
# from qa/$seq
solaris	75	dso	solaris_init	$PCP_PMDAS_DIR/solaris/pmda_solaris.so
pmcd	2	dso	pmcd_init	$PCP_PMDAS_DIR/pmcd/pmda_pmcd.so
End-of-File
elif [ $PCP_PLATFORM = freebsd ]
then
    cat >>$tmp.newconf  <<End-of-File
# from qa/$seq
freebsd	85	dso	freebsd_init	$PCP_PMDAS_DIR/freebsd/pmda_freebsd.so
pmcd	2	dso	pmcd_init	$PCP_PMDAS_DIR/pmcd/pmda_pmcd.so
End-of-File
elif [ $PCP_PLATFORM = openbsd ]
then
    cat >>$tmp.newconf  <<End-of-File
# from qa/$seq
openbsd	139	dso	openbsd_init	$PCP_PMDAS_DIR/openbsd/pmda_openbsd.so
pmcd	2	dso	pmcd_init	$PCP_PMDAS_DIR/pmcd/pmda_pmcd.so
End-of-File
else
    echo "Arrgh ... need pmcd.conf for $PCP_PLATFORM"
    exit 1
fi

_renew_pmcd main

# Start with a fresh pmcd log
#
$sudo $signal -a pmgadgets pmchart pmview >/dev/null 2>&1
if ! _service pmcd restart 2>&1; then _exit 1; fi \
| _filter_pcp_restart
_wait_for_pmcd || _exit 1
if ! _service pmlogger restart 2>&1; then _exit 1; fi \
| _filter_pcp_restart
_wait_for_pmlogger || _exit 1

# Test 2.0 PMDA first
#
_agent_install simple $simple_domain true
_agent_remove simple
_agent_install simple $simple_domain false
_agent_remove simple

# Test 2.0 broken PMDA
#
_broken_install broken_pmda_2_0 2
_agent_remove broken

status=0
exit
